import { Result } from "../result";
import { CssValue, numberMaybePercentage } from "./css";
import * as CssColor from "color";
export declare type ColorRGB = {
  // 0 ~ 255
  R: number;
  // 0 ~ 255
  G: number;
  // 0 ~ 255
  B: number;
};

export declare type ColorHex = string | number;

/**
 * 普通颜色
 */
export declare type ColorOpts = {
  // 颜色值
  value: ColorRGB | ColorHex;
  // 0 ~ 1 表示透明通道值,默认是1,补透明
  A?: number;
};
export class Color extends CssValue<ColorOpts> {
  private getColorLibrary(mixinColor: string, weight: number): Object {
    return CssColor(this.cssValue()).mix(CssColor(mixinColor), weight);
  }
  getLevel(level: number) {
    if (!this.cssValueError()) {
      const absLevel = Math.abs(level);
      let CssObj: any;
      if (absLevel != 0 && absLevel <= 5) {
        CssObj = this.getColorLibrary("white", 0.6 - absLevel / 10);
      } else if (absLevel > 5 && absLevel <= 10) {
        CssObj = this.getColorLibrary("black", absLevel / 10 - 0.5);
      } else {
        CssObj = this.getColorLibrary("white", 0);
      }
      const R = parseInt(CssObj.object().r);
      const G = parseInt(CssObj.object().g);
      const B = parseInt(CssObj.object().b);
      return `rgb(${R},${G},${B})`;
    } else {
      throw new Error(this.cssValueError());
    }
  }
  parseCssValue(opts: ColorOpts): Result<string> {
    if (!opts.value) {
      return Result.fail("颜色值不能为空");
    }
    if (!opts.A) {
      opts.A = 1;
    } else if (opts.A && (opts.A > 1 || opts.A < 0)) {
      return Result.fail(`错误的透明通道值:${opts.A}`);
    }
    let R: number, G: number, B: number;
    if (typeof opts.value == "string" || typeof opts.value == "number") {
      let color: string;
      if (typeof opts.value == "number") {
        color = opts.value.toString(16);
      } else {
        color = opts.value;
        if (color.startsWith("#")) {
          color = color.slice(1);
        }
      }
      // 处理16进制字符串处理
      if (color.length != 6 || Number.isNaN(parseInt(color, 16))) {
        return Result.fail(`错误的十六进制颜色值:${opts.value}`);
      }
      R = parseInt(color.substring(0, 2), 16);
      G = parseInt(color.substring(2, 4), 16);
      B = parseInt(color.substring(4, 6), 16);
    } else {
      // 直接取R,G,B
      R = opts.value.R;
      G = opts.value.G;
      B = opts.value.B;
      if (R > 255 || R < 0 || G > 255 || G < 0 || B > 255 || B < 0) {
        return Result.fail(`错误的RGB颜色值:${opts.value}`);
      }
    }
    let value: string;
    if (opts.A == 1) {
      value = `rgb(${R},${G},${B})`;
    } else {
      value = `rgba(${R},${G},${B},${opts.A})`;
    }
    return Result.succ(value);
  }
}

/**
 * 变化对
 * 例如:red 50% blue 70% yellow 100%
 * 前50%为红色再50%到70%的区间向blue过渡
 * 70%到100%的区间由blue向yellow过渡
 */
export declare type GradientPairOpts = {
  // 颜色
  color: ColorOpts;
  // 过渡比例,0到100的整数(忽略小数点),如果为空代表区间为均匀值
  transition?: number;
};
export class GradientPair extends CssValue<GradientPairOpts> {
  protected parseCssValue(opts: GradientPairOpts): Result<string> {
    let error: string | undefined;
    const color = new Color(opts.color);
    if ((error = color.cssValueError())) {
      return Result.fail(`错误的颜色对象:${error}`);
    }
    let transition: string;
    if (!opts.transition) {
      transition = "";
    } else {
      const transitionNumber = parseInt(opts.transition + "");
      if (
        transitionNumber < 0 ||
        transitionNumber > 100 ||
        Number.isNaN(transitionNumber)
      ) {
        return Result.fail(`错误的过渡数值:${opts.transition}`);
      }
      transition = transitionNumber + "%";
    }
    return Result.succ(`${color.cssValue()} ${transition}`);
  }
}

/**
 * 渐变色,需要匹配css规则background-image,不是color
 */
export declare type GradientColorOpts = {
  // 变色对
  pairs: GradientPairOpts[];
};
export abstract class GradientColor<
  T extends GradientColorOpts
> extends CssValue<T> {
  private pairs: GradientPair[] | undefined;

  constructor(opts: T) {
    super(undefined);
    if (!opts.pairs || opts.pairs.length == 0) {
      this.valueResult = Result.fail("必须传入至少一组渐变色");
      return;
    }
    this.pairs = [];
    for (const p of opts.pairs) {
      this.pairs.push(new GradientPair(p));
    }
    this.valueResult = this.parseCssValue(opts);
  }

  protected parseGradientPair(): Result<string> {
    let error: string | undefined;
    let index: number;
    const resultArray = [];
    for (index = 0; index < this.pairs!.length; index++) {
      const p = this.pairs![index];
      if ((error = p.cssValueError())) {
        break;
      }
      resultArray.push(p.cssValue());
    }
    if (error) {
      return Result.fail(`位置${index}颜色配置出现错误:${error}`);
    }
    return Result.succ(resultArray.join(","));
  }
}

/**
 * 方位名称
 */
export declare type PositionName = "top" | "left" | "right" | "bottom";

/**
 * 线性渐变方向
 */
export declare type LinearDirection =
  | number //整数数值角度(忽略小数点)
  | PositionName // 一个方向
  | [PositionName, PositionName]; // 两个方向

/**
 * 线性渐变色
 */
export declare type LinearGradientColorOpts = {
  // 线性改变的方向,默认:bottom
  direction?: LinearDirection;
} & GradientColorOpts;
export class LinearGradientColor extends GradientColor<LinearGradientColorOpts> {
  parseCssValue(opts: LinearGradientColorOpts): Result<string> {
    const pairsRes = this.parseGradientPair();
    if (!pairsRes.isSuccess()) {
      return pairsRes;
    }
    let direction: string;
    if (!opts.direction) {
      direction = "to bottom";
    } else {
      if (typeof opts.direction == "number") {
        direction = Math.floor(opts.direction) + "deg";
      } else if (typeof opts.direction == "string") {
        direction = `to ${opts.direction}`;
      } else if (opts.direction.join && opts.direction.length > 0) {
        direction = `to ${opts.direction.join(" ")}`;
      } else {
        return Result.fail(`错误的渐变方向参数:${opts.direction}`);
      }
    }
    return Result.succ(`linear-gradient(${direction},${pairsRes.getResult()})`);
  }
}

/**
 * 径向位置
 */
export declare type RadialPositionName = PositionName | "center";

/**
 * 径向大小
 */
export declare type RadialSize =
  | number // 半径大小,小于1表示百分比,大于1代表数值,整数忽略小数值
  | [number, number] // 长半轴和短半轴(椭圆下有效,圆形下退化为取第一个数值)
  | "farthest-corner" // 指定径向渐变的半径长度为从圆心到离圆心最远的角
  | "closest-corner" // 指定径向渐变的半径长度为从圆心到离圆心最近的角
  | "farthest-side" // 指定径向渐变的半径长度为从圆心到离圆心最远的边
  | "closest-side"; // 指定径向渐变的半径长度为从圆心到离圆心最近的边

export declare type RadialPosition =
  | number // 半径大小,小于1表示百分比,大于1代表数值,整数忽略小数值
  | [number, number]
  | RadialPositionName
  | [RadialPositionName, RadialPositionName];

export declare type RadialShape = "ellipse" | "circle";

/**
 * 径向渐变色,按照某种形状进行颜色改变,适应规则background-image
 */
export declare type RadialGradientColorOpts = {
  // 径向形状:ellipse:椭圆,circle:圆形,默认ellipse
  shape?: RadialShape;
  // 形状所在的位置,默认center
  position?: RadialPosition;
  // 径向大小,默认farthest-corner
  size?: RadialSize;
  // 是否径向重复,默认不重复
  repeatable?: boolean;
} & GradientColorOpts;
export class RadialGradientColor extends GradientColor<RadialGradientColorOpts> {
  protected parseCssValue(opts: RadialGradientColorOpts): Result<string> {
    const pairsRes = this.parseGradientPair();
    if (!pairsRes.isSuccess()) {
      return pairsRes;
    }
    const shape: RadialShape = opts.shape ? opts.shape : "ellipse";

    let position: string;
    if (!opts.position) {
      position = "center";
    } else {
      position = this.parsePositionValue(opts.position);
    }

    let size: string;
    if (!opts.size) {
      size = "farthest-corner";
    } else if (typeof opts.size == "string") {
      size = opts.size;
    } else {
      if (typeof opts.size == "number") {
        size = numberMaybePercentage(opts.size);
      } else {
        const ss: Array<string> = [];
        for (const n of opts.size) {
          ss.push(numberMaybePercentage(n));
        }
        size = ss.join(" ");
      }
    }

    return Result.succ(
      `radial-gradient(${shape} ${size} at ${position},${pairsRes.getResult()})`
    );
  }

  private parsePositionValue(position: RadialPosition) {
    const parseSingle = (pos: number | string) => {
      let result!: string;
      if (typeof pos == "string") {
        result = pos;
      } else if (typeof pos == "number") {
        result = numberMaybePercentage(pos);
      }
      return result;
    };
    if (typeof position == "number" || typeof position == "string") {
      return parseSingle(position);
    } else {
      const ps: Array<string> = [];
      for (const p of position) {
        ps.push(parseSingle(p));
      }
      return ps.join(" ");
    }
  }
}
